# [十一]Spring AOP - 代理入口类
# 是否生成代理
当一个bean 实例化完成后,会判断该 bean 是否生成代理: AOP 的入口,找到
doCreateBean()
方法所在类 org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// AOP 的入口方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
进入
initializeBean()
方法所在类 org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// AOP入口的具体生产 代理实例方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
}
}
知识点
applyBeanPostProcessorsAfterInitialization()
方法是一个 BeanPostProcessor
接口的运用,initializeBean
方法我们都知道是一个bean 实例化完成后做的操作,而这个代理实例生成也是在bean 实例化完成后做的操作。
进入
applyBeanPostProcessorsAfterInitialization()
方法所在类 org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory
/**
* TODO: 当bean 实例化完成后的 代理包装
*/
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
进入
BeanPostProcessor
类的postProcessAfterInitialization()
方法找到实现类
AbstractAutoProxyCreator
的postProcessAfterInitialization()
方法所在类 org.springframework.aop.framework.autoproxy.
AbstractAutoProxyCreator
/**
* TODO: 验证
*/
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
进入
wrapIfNecessary()
方法所在类 org.springframework.aop.framework.autoproxy.
AbstractAutoProxyCreator
/**
* TODO: 创建当前bean的代理,核心方法
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 创建当前bean的代理,如果这个bean有advice的话,重点看,重要程度5
// 得到所有的可用于拦截当前 bean 的 advisor、advice、interceptor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果有切面,则生成该bean的代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 把被代理对象bean实例封装到SingletonTargetSource对象中
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
进入
getAdvicesAndAdvisorsForBean()
方法,继续进入findEligibleAdvisors()
方法所在类 org.springframework.aop.framework.autoproxy.
AbstractAdvisorAutoProxyCreator
/**
* TODO:查找@Aspectj注解的类,核心方法
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 找到候选的切面,其实就是一个寻找有@Aspectj注解的过程,
// 把工程中所有有这个注解的类封装成Advisor返回
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 判断候选的切面是否作用在当前beanClass上面,就是一个匹配过程。
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//对有@Order@Priority进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
知识点
如何查找当前bean 的切面
1、从Spring中查找所有的切面
- ①、首先找到所有的
BeanDefinition
对象对应的beanName
,反射拿到对应的 Class 对象,判断该类上面是否有@Aspect
注解,有则是我们要找的; - ② 、 然后循环该Class 里面的除了
@PointCut
注解的方法,找到方法上的Around.class
,Before.class
,After.class
,AfterReturning.class
,AfterThrowing.class
注解,并且把注解里面的信息,比如表达式、argNames、注解类型等信息封装成对象AspectJAnnotation
; - ③ 、接着创建
pointCut
对象,把注解对象中的表达式设置到pointCut
对象中; - ④、最后就是创建
Advice
对象,根据不同的注解类型创建出不同的Advice
对象,对象如 下 :AspectJAroundAdvice,AspectJAfterAdvice, AspectJAfterThrowingAdvice,AspectJMethodBeforeAdvice, AspectJAfterReturningAdvice 最终把注解对应的Advice
对象和pointCut
对象封装成Advisor
对象。
- ①、首先找到所有的
2、找到拦截当前bean的切面
- 从收集到的所有切面中,每一个切面都会有
pointCut
来进行模块匹配,其实这个过程就是一个匹配过程,看看pointCut
表达式中的内容是否包含了当前 bean,如果包含了,那么这个 bean 就有切面,就会生成代理。
- 从收集到的所有切面中,每一个切面都会有
# 代理类的调用
//创建当前bean的代理,如果这个bean有advice的话,重点看,重要程度5
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
//如果有切面,则生成该bean的代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//把被代理对象bean实例封装到SingletonTargetSource对象中
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
当
getAdvicesAndAdvisorsForBean()
方法拦截到有advice的类,如果返回的Object[] specificInterceptors
数组不为空,最终会执行到createProxy()
,这个方法就会生成 bean的代理实例。进入
createProxy
方法所在类 org.springframework.aop.framework.
AbstractAutoProxyCreator
/**
* TODO : 创建代理实例
* @param beanClass 类对象
* @param beanName bean 名字
* @param specificInterceptors 拦截到的所有的 advisors
* @param targetSource 具体类实现的信息(被代理实例)
* @return
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建代理工厂实例
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
// proxyTargetClass 是否对类进行代理,而不是对接口进行代理,
// 设置为true时,使用CGLib代理。
proxyFactory.setProxyTargetClass(true);
}
else {
// 1. 有接口的,循环调用:proxyFactory.addInterface(ifc);
// 2. 没有接口的,调用:proxyFactory.setProxyTargetClass(true);
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 把 advice 类型的增强包装成 advisor 切面
// 返回匹配了当前 bean 的 advisors 数组
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
// 用来控制代理工厂被配置后,是否还允许修改代理的配置,默认为false
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 获取代理实例
return proxyFactory.getProxy(getProxyClassLoader());
}
进入
buildAdvisors
方法所在类 org.springframework.aop.framework.
AbstractAutoProxyCreator
/**
* TODO : 包装成 advisor 切面的过程
*/
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// 自定义 MethodInterceptor 拿到 AnnotationAwareAspectJAutoProxyCreator
// 对象调用 setInterceptorNames方法
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors.length > 0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
if (logger.isTraceEnabled()) {
int nrOfCommonInterceptors = commonInterceptors.length;
int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
}
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
// 对自定义的 advice要进行包装,把 advice包装成 advisor对象,切面对象
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
执行完
buildAdvisors
方法,返回匹配了当前 bean 的 advisors 数组继续执行
createProxy
方法,进入getProxy()
方法所在类 org.springframework.aop.framework.
ProxyFactory
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
进入
createAopProxy()
方法所在类 org.springframework.aop.framework.
ProxyCreatorSupport
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 创建一个 AopProxy 的实例
return getAopProxyFactory().createAopProxy(this);
}
创建
createAopProxy()
方法 之前,需要拿到一个AopProxyFactory
实例进入
getAopProxyFactory()
方法所在类 org.springframework.aop.framework.
ProxyCreatorSupport
public class ProxyCreatorSupport extends AdvisedSupport {
private AopProxyFactory aopProxyFactory;
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}
}
很明显,拿到的
this.aopProxyFactory
的值,来自构造方法new DefaultAopProxyFactory()
进入
DefaultAopProxyFactory
类的createAopProxy()
方法所在类 org.springframework.aop.framework.
DefaultAopProxyFactory
/**
* TODO : 创建 AopProxy 代理实例
*/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果要代理的类本身就是接口,创建一个新的 JDK代理实例,多例模式
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则使用 Cglib 代理
// ObjenesisCglibAopProxy 在Spring4.0 就有了
return new ObjenesisCglibAopProxy(config);
}
else {
// 如果有接口,创建一个新的 JDK代理实例,多例模式
return new JdkDynamicAopProxy(config);
}
}
知识点
- 如果被代理的目标类实现了一个或多个自定义的接口,那么就会使用 JDK 动态代理;
- 如果被代理的目标类没有实现任何接口,会使用 CGLIB 实现代理;
- 如果设置了
proxyTargetClass="true"
,那么都会使用 CGLIB生成代理;
总结:
JDK 动态代理基于接口,所以只有接口中的方法会被增强(因为代理类已经继承了Proxy),而 CGLIB 基于类继承,如果目标类中的方法使用了final
或private
关键字来修饰,是不能被增强的。
当被代理的目标类是基于JDK的动态代理,进入
JdkDynamicAopProxy()
的构造方法所在类 org.springframework.aop.framework.
JdkDynamicAopProxy
// 代理工厂对象(保存这个AOP代理所有的配置信息 包括所有的增强器等等)
private final AdvisedSupport advised;
//......省略无关代码
/**
* TODO : 根据参数中指定的配置(config)构造一个新的JdkDynamicAopProxy
*/
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
// 校验:必须有至少一个增强器和目标实例
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
到此,已经创建好了
AopProxy
,返回到最初的getProxy()
方法
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
拿到了
AopProxy
,接着可以调用到了getProxy()
方法进入
getProxy()
最核心的方法所在类 org.springframework.aop.framework.
JdkDynamicAopProxy
/**
* TODO : 创建JDK动态代理实例
*/
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
/**
* TODO : 查找接口(advised 是代理工厂对象)
* 我们看到最终代理的接口就是这里返回的所有接口们(除了我们自己的接口,还有Spring默认的一些接口)
* 大致过程如下:
* 1、获取目标对象自己实现的接口(最终肯定都会被代理的)
* 2、是否添加`SpringProxy`这个接口:目标对象实现对就不添加了,没实现过就添加true
* 3、是否新增`Adviced`接口,注意不是Advice通知接口。 实现过就不实现了,
* 没实现过并且advised.isOpaque()=false就添加(默认是会添加的)
* 4、是否新增DecoratingProxy接口。传入的参数decoratingProxy为true,
* 并且没实现过就添加(显然这里,首次进来是会添加的)
* 5、代理类的接口一共是目标对象的接口+上面三个接口SpringProxy、Advised、DecoratingProxy
* (SpringProxy是个标记接口而已,其余的接口都有对应的方法的)
* 备注:DecoratingProxy 这个接口是 Spring4.3后才提供
*/
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 第三个参数传的 this,处理器就是当前类(实现了 InvocationHandler 接口)
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
拿到代理对象调用,以 jdk 动态代理为例(Cglib 是一样的调用逻辑)。 当发生代理对象调用时,会调用到实现了 invocationHandler 接口的类,这个类就
JdkDynamicAopProxy
,然后会调用到该类的 invoke 方法。
进入
invoke()
方法所在类 org.springframework.aop.framework.
JdkDynamicAopProxy
说明
JdkDynamicAopProxy
本身实现了InvocationHandler
接口和AopProxy
接口所以 JdkDynamicAopProxy
实现的InvocationHandler.invoker()
方法就是Proxy
对象回调
的方法。实现的AopProxy.getProxy()
方法就是通过JDK动态代理生成的代理对象,传递的InvocationHandler
对象就是 JdkDynamicAopProxy
自身。这就是动态代理了,切面的业务就是在 invoke()
方法中体现的。具体业务在源码中体现。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
// 从代理工厂中拿到 TargetSource 对象,该对象包装了被代理实例 bean
// 因为 InvocationHandler 持久的就是 targetSource,最终通过 getTarget 拿到目标对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 被代理对象的 equals方法和 hashCode方法是不能被代理的,不会走切面
// 所以此处做了处理 :
// equalsDefined为false(表示自己没有定义过 equals方法) 那就交给代理去比较
// hashCode同理,只要你自己没有实现过此方法,那就交给代理类处理
// 需要注意的是:这里统一指的是,如果接口上有此方法,但是你自己并没有实现 equals和 hashCode
// 方法,那就走AOP这里的实现
// 如过接口上没有定义此方法,只是实现类里自己 @Override了 HashCode,那是无效的,
// 就不做特殊处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
// DecoratingProxy的方法和Advised接口的方法都是最终调用了config,也就是this.advised去执行的
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
// 这个是最终该方法的返回值
Object retVal;
// 是否暴露代理对象,默认false可配置为true,如果暴露就意味着允许在线程内共享代理对象,
// 注意这是在线程内,也就是说同一线程的任意地方都能通过 AopContext 获取该代理对象,
// 这里缓存一份代理对象在 oldProxy
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 通过目标源获取目标对象,这个 target 就是目标对象(被代理实例)
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取作用在这个方法上的所有拦截器链
//会根据切点表达式去匹配这个方法。因此其实每个方法都会进入这里,只是有很多方法的拦截器链是空的
//从代理工厂中拿过滤器链 Object是一个 MethodInterceptor类型的对象,其实就是一个advice对象
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 如果该方法没有执行链,则说明这个方法不需要被拦截,则直接反射调用
if (chain.isEmpty()) {
// 若拦截器为空,那就直接调用目标方法了
// 对参数进行适配:主要处理一些数组类型的参数,看是表示一个参数还是表示多个参数
// (可变参数最终到此都是数组类型,所以最好是需要一次适配)
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 直接通过反射调用目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建一个 invocation ,此处为 ReflectiveMethodInvocation 最终是通过它,
// 去执行前置加强、后置加强等逻辑
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 此处会执行所有的拦截器链 交给Spring AOP的 MethodInvocation 去处理。
// 其实现还是 Spring 的 ReflectiveMethodInvocation
retVal = invocation.proceed();
}
// Massage return value if necessary.
// 获取返回值的类型
Class<?> returnType = method.getReturnType();
// 判断条件,如果返回值不为空,且为目标对象的话,就直接将目标对象赋值给 retVal
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
// 返回 null,并且还不是 Void类型,抛出异常
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
// 释放目标对象(被代理实例)
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
// 把老的代理对象重新 set进去
AopContext.setCurrentProxy(oldProxy);
}
}
}
知识点
- 除了实现类里自己写的方法(接口上没有的),其余方法统一都会进入代理得
invoke()
方法里面。只是invoke
上做了很多特殊处理,比如DecoratingProxy
和Advised
等等的方法,都是直接执行了。 object
的方法中,被代理对象的equals
方法和hashCode
方法是不能被代理的,不会被增强,但是toString()
方法会被增强(不确定AdvisedSupport#methodCache
这个字段事什么时候把toString()方法缓存上的,打断点都没跟踪上)- 生成出来的代理对象,Spring默认都给你实现了接口:
SpringProxy、DecoratingProxy、Advised
# 创建代理的过程
- 1、创建代理工厂对象 ProxyFactory
- 2、切面对象重新包装,会把自定义的 MethodInterceptor 类型的类包装成 Advisor 切面类并加入到代理工厂中
- 3、根据proxyTargetClass 参数和是否实现接口来判断是采用 jdk 代理还是cglib 代理
- 4、创建代理对象,并且把代理工厂对象传递到 jdk 和 cglib 中,注意这里的代理对象和 jdk 类和 cglib 类是一一对应的。
# AOP问题汇总
问题一
实际生成的动态代理在哪里?
参考答案
生成的动态代理($Proxy0)是在JVM内存中的,一般情况是,先把java文件编译成class文件,然后类加载器加载这个class字节码文件,从而让JVM可以生成这个类的对象。但动态代理是,在内存中生成这些字节码,然后再正常地加载字节码,生成对象。
问题二
一个类中的方法如果有代理实例,那么这个代理实例会被IOC容器管理吗?
参考答案
问题三
AOP 拦截器调用如何实现的?
参考答案
如果是JDK实现的代理对象就会通过InvocationHandler
来完成拦截器回调,如果是CGLIB 就通过DynamicAdvisedInterceptor
来完成回调。
扩展阅读
通过AopProxy 对象封装target 目标对象之后,ProxyFactoryBean方法得到的对象已经是一个AopProxy代理对象了,在ProxyFactoryBean 中配置的target目标对象不会让应用直接调用其方法的实现,对target目标对象的方法调用会被AopProxy代理对象拦截,对于不同的AopProxy代理对象生成方式,会使用不同的拦截回调入口。对于 JDK的AopProxy代理对象,使用的是InvocationHander的invoker 回调入口。对于CGLIB的AopProxy代理对象,使用的是设置好的callbak 回调,在这里callback回调中,对于AOP的实现是通过DynamicAdvisedInterceptor 来完成的,DynamicAdvisedInterceptor 的回调入口是 intercept 方法。
问题四
Aspect 注解的类搜集方法的时候,为什么只循环没有@Pointcut 注解的方法?
参考答案
因为@Pointcut 只是切点表达式,不是通知方法
问题五
为什么依赖注入到三级缓存的是代理实例,而不是当前bean实例本身?
参考答案
因为Spring遵循了开闭原则,对修改关闭,对扩展开发,由于很多时候我们并不需要bean实例本身,而是需要修改后的实例,这样通过获取代理对象实例,可以更好的执行业务逻辑。
问题六
为什么实例化之前自定义代理保存到了三级缓存,拿到的却是bean实例本身?
参考答案
问题七
如何自定义一个拦截器链,添加到现在有的连接器链中?
参考答案
实现MethodInterceptor接口